﻿using System;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using HtmlAgilityPack;

class Program
{
    static readonly HttpClient client = new HttpClient();
    static ConcurrentDictionary<string, List<string>> phoneToUrls = new();
    static ConcurrentBag<string> visitedUrls = new();
    static Regex phoneRegex = new(@"\b(0\d{2,3}-?\d{7,8})\b", RegexOptions.Compiled);

    static async Task Main()
    {
        Console.Write("请输入关键词：");
        string keyword = Console.ReadLine();

        Console.WriteLine("正在搜索并抓取页面，请稍候...");

        List<string> resultUrls = await GetSearchResultUrls(keyword);
        await CrawlAndExtract(resultUrls);

        // 展示已爬取的 URL
        Console.WriteLine("\n已爬取的URL：");
        foreach (var url in visitedUrls)
            Console.WriteLine(url);

        // 展示结果
        Console.WriteLine($"\n共找到 {phoneToUrls.Count} 个高校电话号码：");
        foreach (var kv in phoneToUrls)
        {
            Console.WriteLine($"{kv.Key} 出现在以下页面：");
            foreach (var url in kv.Value)
                Console.WriteLine("  - " + url);
        }
    }

    static async Task<List<string>> GetSearchResultUrls(string keyword)
    {
        var searchUrl = $"https://www.bing.com/search?q={Uri.EscapeDataString(keyword + " site:.edu.cn")}";
        string html = await client.GetStringAsync(searchUrl);
        var doc = new HtmlDocument();
        doc.LoadHtml(html);

        var urls = new List<string>();
        foreach (var node in doc.DocumentNode.SelectNodes("//li[@class='b_algo']//h2/a"))
        {
            string? href = node.GetAttributeValue("href", null);
            if (href != null && href.StartsWith("http"))
                urls.Add(href);
        }

        return urls.Distinct().Take(30).ToList(); // 限制30个初始URL
    }

    static async Task CrawlAndExtract(List<string> urls)
    {
        var tasks = urls.Select(url => Task.Run(async () =>
        {
            try
            {
                if (visitedUrls.Contains(url)) return;
                visitedUrls.Add(url);

                string html = await client.GetStringAsync(url);
                var phones = phoneRegex.Matches(html);

                foreach (Match match in phones)
                {
                    string phone = match.Value;
                    phoneToUrls.AddOrUpdate(phone,
                        new List<string> { url },
                        (key, existing) =>
                        {
                            if (!existing.Contains(url))
                                existing.Add(url);
                            return existing;
                        });

                    if (phoneToUrls.Count >= 100) return;
                }
            }
            catch { /* 忽略错误 */ }
        }));

        await Task.WhenAll(tasks);
    }
}
